

package com.maoshi.shop.security.api.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.emoji.EmojiUtil;
import com.alipay.api.domain.PrincipalInfo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.maoshi.shop.bean.model.User;
import com.maoshi.shop.common.exception.MaoshiShopBindException;
import com.maoshi.shop.common.util.IPHelper;
import com.maoshi.shop.common.util.PrincipalUtil;
import com.maoshi.shop.dao.UserMapper;
import com.maoshi.shop.security.api.model.MaoshiUser;
import com.maoshi.shop.security.api.service.MaoshiUserDetailsService;
import com.maoshi.shop.security.comment.dao.AppConnectMapper;
import com.maoshi.shop.security.comment.enums.App;
import com.maoshi.shop.security.comment.exception.UsernameNotFoundException;
import com.maoshi.shop.security.comment.model.AppConnect;
import com.maoshi.shop.security.comment.service.AppConnectService;
import com.maoshi.shop.security.comment.service.impl.AppConnectServiceImpl;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.Objects;

/**
 * 用户详细信息
 *
 * @author
 */
@Slf4j
@Primary
@Service
@AllArgsConstructor
public class MaoshiUserServiceImpl implements MaoshiUserDetailsService {

	private final UserMapper userMapper;

	private final AppConnectMapper appConnectMapper;

	private final AppConnectService appConnectService;


	@Override
	public MaoshiUser loadUserByUsername(String principal) {
		throw new MaoshiShopBindException("未实现该登陆方法");
	}

	/**
	 * @param principal userNameOrMobile
	 * @param appType 见 APP
	 * @return
	 */
	@Override
	public MaoshiUser loadUserByMobileOrUserName(String principal, Integer appType, Integer loginType) {

		User user = loadUserByMobileOrUserName(principal, loginType);


		// 如果是手机验证码登陆，直接给他注册一个用户
		if (Objects.equals(loginType, 1) && user == null) {
			user = new User();
			Date now = new Date();
			user.setModifyTime(now);
			user.setUserRegtime(now);
			user.setUserRegip(IPHelper.getIpAddr());
			user.setStatus(1);
			user.setUserMobile(principal);
			user.setUserName(principal);
			// 用户名就是默认的昵称
			user.setNickName(principal);
			appConnectService.registerOrBindUser(user, null, appType);
		}

		if (user == null) {
			throw new UsernameNotFoundException("用户不存在");
		}
		//
		AppConnect appConnect = appConnectMapper.getByUserId(user.getUserId(), appType);
		if (appConnect == null) {
			appConnectService.registerOrBindUser(user, null, appType);
		}
		return getMaoshiUser(appType, user, appConnect == null? null:appConnect.getBizUserId());
	}

	@Override
	public MaoshiUser loadUserByAppConnect(AppConnect appConnect) {

		if (StrUtil.isBlank(appConnect.getUserId())) {
			MaoshiUser maoshiUser = new MaoshiUser();
			maoshiUser.setUserId(appConnect.getUserId());
			maoshiUser.setBizUserId(appConnect.getBizUserId());
			maoshiUser.setAppType(appConnect.getAppId());

			// 没有userId一样可以用，只不过不能进行下单的流程而已咯
			maoshiUser.setEnabled(true);
			return maoshiUser;
		}
		User user = userMapper.selectById(appConnect.getUserId());
		return getMaoshiUser(appConnect.getAppId(), user, appConnect.getBizUserId());
	}

	@Override
	public User loadUserByMobileOrUserName(String mobileOrUserName, Integer loginType) {
		User user = null;
		// 手机验证码登陆，或传过来的账号很像手机号
		if (Objects.equals(loginType, 1) || PrincipalUtil.isMobile(mobileOrUserName)) {
			user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUserMobile, mobileOrUserName));
		}
		// 如果不是手机验证码登陆， 找不到手机号就找用户名
		if  (!Objects.equals(loginType, 1) && user == null) {
			user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUserName, mobileOrUserName));
		}
		return user;
	}

	@Override
	public MaoshiUser getMaoshiUser(Integer appId, User user, String bizUserId) {
		String name = StrUtil.isBlank(user.getRealName()) ? user.getNickName() : user.getRealName();
		MaoshiUser maoshiUser = new MaoshiUser();
		maoshiUser.setEnabled(user.getStatus() == 1);
		maoshiUser.setUserId(user.getUserId());
		maoshiUser.setBizUserId(bizUserId);
		maoshiUser.setAppType(appId);
		maoshiUser.setName(name);
		maoshiUser.setPic(user.getPic());
		maoshiUser.setPassword(user.getLoginPassword());
		return maoshiUser;
	}


	@Override
	@Transactional(rollbackFor = Exception.class)
	// 使用唯一索引，不用锁
//	@RedisLock(lockName = "insertUser", key = "#appConnect.appId + ':' + #appConnect.bizUserId")
	@CacheEvict(cacheNames = "AppConnect", key = "#appConnect.appId + ':' + #appConnect.bizUserId")
	public void insertUserIfNecessary(AppConnect appConnect) {
		// 进入锁后再重新判断一遍用户是否创建
		AppConnect dbAppConnect = appConnectMapper.getByBizUserId(appConnect.getBizUserId(), appConnect.getAppId());
		if(dbAppConnect != null) {
			return;
		}

		String bizUnionId = appConnect.getBizUnionid();
		String userId = null;
		User user;

		if (StrUtil.isNotBlank(bizUnionId)) {
			userId = appConnectMapper.getUserIdByUnionId(bizUnionId);
		}
		if (StrUtil.isBlank(userId)) {
			userId = IdUtil.simpleUUID();
			Date now = new Date();
			user = new User();
			user.setUserId(userId);
			user.setModifyTime(now);
			user.setUserRegtime(now);
			user.setStatus(1);
			user.setNickName(EmojiUtil.toAlias(StrUtil.isBlank(appConnect.getNickName()) ? "" : appConnect.getNickName()));
			user.setPic(appConnect.getImageUrl());
			userMapper.insert(user);
		} else {
			user = userMapper.selectById(userId);
		}

		appConnect.setUserId(user.getUserId());

		appConnectMapper.insert(appConnect);
	}
	/**
	 * 获取前端登陆的用户信息
	 *
	 * @param app
	 * @param bizUserId openId
	 * @return UserDetails
	 * @throws UsernameNotFoundException
	 */
	@Override
	public MaoshiUser loadUserByAppIdAndBizUserId(App app, String bizUserId) {

		User user = userMapper.getUserByBizUserId(app.value(), bizUserId);
		if (user == null) {
			throw new UsernameNotFoundException("无法获取用户信息");
		}

		return getMaoshiUser(app.value(), user, bizUserId);
	}

}
